#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <poll.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/gpio.h>

#define HELLO_DBG
#ifdef HELLO_DBG
#define hello_dbg(fmt, ...) printf("[%s][%d]" fmt "\r\n", __func__, __LINE__, ##__VA_ARGS__)
#else
#define hello_dbg(fmt, ...)
#endif

#define DEV_NMAE "/dev/spidev0.0"
#define GPIO_DEV_NMAE "/dev/gpiochip0"

#define ST77XX_REG_RDDID (0x04)

static int fd;
static int gpio_fd;

static int st77xx_gpio_init(void)
{
    int fd;
    int ret;

    fd = open(GPIO_DEV_NMAE, O_RDWR);
    if (fd < 0)
    {
        hello_dbg("open %s error, erron:%d:%s", GPIO_DEV_NMAE, errno, strerror(errno));
        return -errno;
    }

    struct gpio_v2_line_request req;

    memset(&req, 0, sizeof(req));
    req.offsets[0] = 2; // pa2 -> dc
    req.offsets[1] = 0; // pa0 -> backlight
    req.config.flags = GPIO_V2_LINE_FLAG_OUTPUT;
    strcpy(req.consumer, "st77xx");
    req.num_lines = 2;

    ret = ioctl(fd, GPIO_V2_GET_LINE_IOCTL, &req);
    if (ret == -1)
    {
        hello_dbg("Failed to issue GPIO_V2_GET_LINE_IOCTL (%d), %s", ret, strerror(errno));
        close(fd);
        return -errno;
    }
    close(fd);

    gpio_fd = req.fd;

    return 0;
}

static void st77xx_gpio_set(uint8_t mask, uint8_t bits)
{
    int ret;
    struct gpio_v2_line_values values;

    values.mask = mask;
    values.bits = bits;

    ret = ioctl(gpio_fd, GPIO_V2_LINE_SET_VALUES_IOCTL, &values);
    if (ret == -1)
    {
        hello_dbg("Failed to issue GPIO_V2_LINE_SET_VALUES_IOCTL (%d), %s", ret, strerror(errno));
    }
}

// dc==0 > command, dc==1 -> data
static void st77xx_gpio_set_dc(uint8_t dc)
{
    st77xx_gpio_set(1, dc ? 1 : 0);
}

static void st77xx_gpio_set_backlight(uint8_t on)
{
    int bits = on ? 1 : 0;
    st77xx_gpio_set(1 << 1, bits << 1);
}

static void spi_set_bus_attr()
{
}

static void st77xx_read_id()
{
    int len;
    uint8_t reg[] = {ST77XX_REG_RDDID};
    uint8_t data[4] = {1};

    st77xx_gpio_set_dc(0);
    len = write(fd, reg, sizeof(reg));
    printf("[%s][%d] write return len:%d\r\n", __func__, __LINE__, len);

    st77xx_gpio_set_dc(1);
    memset(data, 0, sizeof(data));
    len = read(fd, data, sizeof(data));
    printf("[%s][%d] read %d return len:%d, 0x%x, 0x%x, 0x%x, 0x%x\r\n", __func__, __LINE__,
           sizeof(data), len, data[0], data[1], data[2], data[3]);
}

int main(void)
{
    int ret;

    hello_dbg("%s, %s", __DATE__, __TIME__);

    fd = open(DEV_NMAE, O_RDWR);
    if (fd < 0)
    {
        hello_dbg("open %s error, erron:%d:%s", DEV_NMAE, errno, strerror(errno));
        return -1;
    }

    ret = st77xx_gpio_init();
    if (ret < 0)
    {
        hello_dbg("st77xx_gpio_init error:%d", ret);
        close(fd);
        return ret;
    }

    st77xx_gpio_set_backlight(1);

    st77xx_read_id();

    sleep(1);
    st77xx_gpio_set_backlight(0);

    close(fd);
    close(gpio_fd);

    return 0;
}
